#include "c_dchain.h"

C_DCHAIN* dchain_Create_Ex(C_DCHAIN *tag_dchain,size_t data_size,void (*free_fun)(void *tag_data))
{
	if(tag_dchain==NULL)return NULL;
	
	tag_dchain->dchain_head=NULL;
	if(pool_Create(&tag_dchain->data_pool,data_size+sizeof(C_DCHAIN))==NULL)return NULL;
	
	tag_dchain->dchain_length=0;
	tag_dchain->data_size=data_size;
	tag_dchain->free_fun=free_fun;
	
	return tag_dchain;
};

void* dchain_Append(const void *in_data,C_DCHAIN *tag_dchain)
{
	DCHAIN_HEAD *new_op;
	
	new_op=pool_Malloc(&tag_dchain->data_pool);
	++new_op;
	dchain_Next(new_op)=NULL;
	MEMCPY_(new_op,in_data,tag_dchain->data_size);
	if(tag_dchain->dchain_head!=NULL)
	{
		/*dchain_Head(new_op)->prev=tag_dchain->dchain_tail;*/
		dchain_Prev(new_op)=tag_dchain->dchain_tail;
		(dchain_Head(tag_dchain->dchain_tail))->next=new_op;
		tag_dchain->dchain_tail=new_op;
	}
	else
	{
		dchain_Prev(new_op)=NULL;
		tag_dchain->dchain_head=new_op;
		tag_dchain->dchain_tail=new_op;
	};
	++tag_dchain->dchain_length;
	return (void*)new_op;
};

void* dchain_Insert(const void *in_data,void *in_cur,C_DCHAIN *tag_dchain)
{
	DCHAIN_HEAD *head;

	head=pool_Malloc(&tag_dchain->data_pool);
	++head;
	MEMCPY_(head,in_data,tag_dchain->data_size);
	if(dchain_Prev(in_cur)!=NULL)
	{
		dchain_Next(dchain_Prev(in_cur))=head;
		dchain_Prev(head)=dchain_Prev(in_cur);
		dchain_Next(head)=in_cur;
		dchain_Prev(in_cur)=head;
	}
	else
	{
		dchain_Next(head)=in_cur;
		dchain_Prev(head)=NULL;
		dchain_Prev(in_cur)=head;
		tag_dchain->dchain_head=head;
	};
	return head;
};

void dchain_Remove(void *in_cur,C_DCHAIN *tag_dchain)
{
	DCHAIN_HEAD *head;

	if(dchain_Prev(in_cur)!=NULL)
	{
		dchain_Next(dchain_Prev(in_cur))=dchain_Next(in_cur);
		if(dchain_Next(in_cur)==NULL)tag_dchain->dchain_tail=dchain_Prev(in_cur);
		else
		{
			dchain_Prev(dchain_Next(in_cur))=dchain_Prev(in_cur);
		};
	}
	else
	{
		tag_dchain->dchain_head=dchain_Next(in_cur);
		if(dchain_Next(in_cur)!=NULL)dchain_Prev(dchain_Next(in_cur))=NULL;
		else
		{
			tag_dchain->dchain_head=NULL;
			tag_dchain->dchain_tail=NULL;
		};
		if(dchain_Next(in_cur)==NULL)tag_dchain->dchain_tail=dchain_Next(in_cur);
	};
	head=in_cur;
	dchain_Next(head)=NULL;
	dchain_Prev(head)=NULL;
	--head;
	pool_Free(head,&tag_dchain->data_pool);
};

void dchain_Drop(C_DCHAIN *tag_dchain)
{
	void *tmp_ptr;
	
	if(tag_dchain->free_fun!=NULL&&tag_dchain->dchain_length>0)for(tmp_ptr=dchain_First(tag_dchain);tmp_ptr!=NULL;tmp_ptr=dchain_Next(tmp_ptr))tag_dchain->free_fun(*(void**)tmp_ptr);
	pool_Drop(&tag_dchain->data_pool);
};
